using System;
using System.Globalization;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell;

namespace AntEater.Integration.Attributes
{
    /// <summary>
    /// This attribute adds a logical view to the editor created by an editor factory.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
    [ComVisibleAttribute(false)]
    public sealed class ProvideEditorXmlDesignerViewAttribute : RegistrationAttribute
    {
        private Guid _factory;
        private Type _factoryType;
        private Guid _logicalView;
        private string _name;
        private string _fileExtension;
        private string _xmlNamespace;
        private bool _matchBoth;

        /// <summary>
        /// Creates a new RegisterEditorLogicalView attribute to register a logical
        /// view provided by your editor.
        /// </summary>
        /// <param name="factoryType">The type of factory; can be a Type, a GUID or a string representation of a GUID</param>
        /// <param name="logicalViewGuid">The guid of the logical view to register.</param>
        public ProvideEditorXmlDesignerViewAttribute(Type factoryType, string logicalViewGuid) {

            if (factoryType == null) { throw new ArgumentNullException("factoryType"); }

            this._factory = factoryType.GUID;
            this._factoryType = factoryType; 
            this._logicalView = new Guid(logicalViewGuid);
        }

        /// <summary>
        /// Gets the type of the factory.
        /// </summary>
        /// <value>The type of the factory.</value>
        public Type FactoryType {
            get { return _factoryType; }
        }


        /// <summary>
        /// Gets the logical view GUID.
        /// </summary>
        /// <value>The logical view GUID.</value>
        public string LogicalViewGuid {
            get { return _logicalView.ToString(); }
        }

        /// <summary>
        /// Gets the logical view.
        /// </summary>
        /// <value>The logical view.</value>
        public Guid LogicalView {
            get { return _logicalView; }
        }

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        public string Name {
            get { return _name; }
            set { _name = value; }
        }

        /// <summary>
        /// Gets or sets the XML namespace.
        /// </summary>
        /// <value>The XML namespace.</value>
        public string XmlNamespace {
            get { return _xmlNamespace; }
            set { _xmlNamespace = value; }
        }

        /// <summary>
        /// Gets or sets the file extension.
        /// </summary>
        /// <value>The file extension.</value>
        public string FileExtension {
            get { return _fileExtension; }
            set { _fileExtension = value; }
        }

        /// <summary>
        /// Get or Set the whether the XML files that support this view must
        /// match both the file extension and the namespace (Match = "both")
        /// or it is OK to merely match the file extension (Match not specified)
        /// </summary>
        /// <value><c>true</c> if match both; otherwise, <c>false</c>.</value>
        public bool MatchBoth {
            get { return _matchBoth; }
            set { _matchBoth = value; }
        }

        /// <summary>
        /// Gets the registry path.
        /// </summary>
        /// <value>The registry path.</value>
        private string RegistryPath {
            get { return string.Format(CultureInfo.InvariantCulture, "XmlDesigners\\{0}", _factory.ToString("B")); }
        }

        /// <summary>
        /// Registers this instance.
        /// </summary>
        /// <param name="context">The context.</param>
        public override void Register(RegistrationContext context) {

            if (context == null) { throw new ArgumentNullException("context"); }

            using (Key childKey = context.CreateKey(RegistryPath)) {

                childKey.SetValue("Editor", _factory.ToString("D"));
                childKey.SetValue("LogicalView", _logicalView.ToString("D"));

                if (_name == null) {
                    _name = string.Empty;
                }

                childKey.SetValue(null, _name);

                if (_xmlNamespace != null) {
                    childKey.SetValue("Namespace", _xmlNamespace);
                }

                if (_fileExtension != null) {
                    childKey.SetValue("Extension", _fileExtension);
                }

                if (_matchBoth) {
                    childKey.SetValue("Match", "both");
                }
            }
        }

        /// <summary>
        /// Unregister this instance.
        /// </summary>
        /// <param name="context">The context.</param>
        public override void Unregister(RegistrationContext context) {

            if (context == null) { throw new ArgumentNullException("context"); }

            context.RemoveKey(RegistryPath);
        }
    }
}
